package com.sunrise.gateway.commons;

import com.alibaba.fastjson.JSON;
import com.dap.cache.common.RedisComponentInterface;
import com.dap.exception.BusinessException;
import com.dap.param.ControlData;
import com.dap.param.StringInput;
import com.dap.utils.LongStringIdUtil;
import com.dap.utils.Md5Util;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public abstract class UriFilterUtils {
    private final static Logger logger = LoggerFactory.getLogger(UriFilterUtils.class);


    // 将StringInput输入参数的关键信息组合成为字符串, 用来判断StringInput的唯一性
    private static String generateStringInputUniqueInputInfoStr(final String group, final StringInput stringInput) {
        String body = stringInput.getBody();
        String bodyUniqueStr;
        if (null == body) {
            bodyUniqueStr = "0_null";
        } else {
            bodyUniqueStr = body.length() + "_" + (body.length()>100 ? Md5Util.md5(body) : body);
        }

        final ControlData ctrlData = stringInput.getCtrlData();
        return ctrlData.getSessionId()
                + "_" + bodyUniqueStr
                + "_" + group + "_" + ctrlData.getPageSize() + "_" + ctrlData.getPageIndex();
    }


    protected static final Set<String> uncheckUriSet = new HashSet<>();
    static {
        try {
            uncheckUriSet.addAll(MyClassPathResourceReader.read("config/uncheck_uris.config"));
        } catch (Exception e) {
            logger.error("", e);
        }

        logger.info("uncheckUriSet size={}, content={}", uncheckUriSet.size(), JSON.toJSONString(uncheckUriSet));
    }


    protected static final ArrayList<String> readKeywords = Lists.newArrayList(
            "query",
            "select",
            "count",
            "get"
    );
    protected static final ArrayList<String> writeKeywords = Lists.newArrayList(
            "update",
            "insert",
            "add",
            "delete",
            "remove",
            "apply",
            "set",
            "bind",
            "unbind",
            "confirm",
            "cancel"
    );

    private static boolean hasKeyWord(String uri, List<String> keywords) {
        uri = uri.toLowerCase();
        for (String keyword : keywords) {
            if (uri.lastIndexOf(keyword) >= 0) {
                return true;
            }
        }
        return false;
    }

    private static boolean isCheckRequest(String uri, String appEnv) {
        if (uncheckUriSet.contains(uri)) {
            return false;
        }

        if ("product".equals(appEnv)) {
            return hasKeyWord(uri, writeKeywords) && !hasKeyWord(uri, readKeywords);
        } else {
            return true;
        }
    }

    // 过滤频繁的重复请求
    public static void filterFrequentlyRepeatRequest(String group, StringInput stringInput, RedisComponentInterface jedis, long expireMilliseconds, String appEnv) {
        if (!isCheckRequest(group, appEnv)) {
            return;
        }

        String currentRequestStr = UriFilterUtils.generateStringInputUniqueInputInfoStr(group, stringInput);

        final String uuid = LongStringIdUtil.generateId();
        String setResult = null;
        try {
            setResult = jedis.setnxExpire(Constants.SESSION_LAST_REQUEST_KEY, currentRequestStr, expireMilliseconds, uuid);
        } catch (Exception e) {
            logger.info("", e);
        }

        if (setResult != null && !"OK".equals(setResult)) {
            logger.info("重复请求:{}\n{}", group, JSON.toJSONString(stringInput));
            throw new BusinessException(com.dap.commons.Constants.ResponseCode.GENERAL_EXCEPTION, "请求过于频繁，请稍后再试");
        }
    }
}
